package xredis

import (
	"errors"
	"fmt"
	"sync"
	"time"
	
	"github.com/go-redis/redis"
	"github.com/spf13/viper"
)

const errConfigKeyNil = "redis config nil: %s"

type clients struct {
	clients map[string]*redis.Client
	sync.RWMutex
}

func(c *clients)add(name string, client *redis.Client){
	if client == nil || len(name) == 0{
		return
	}
	c.Lock()
	defer c.Unlock()
	c.clients[name] = client
}

func (c *clients)get(name string) *redis.Client {
	c.Lock()
	defer c.Unlock()
	return c.clients[name]
}

func (c *clients)del(name string)  {
	c.Lock()
	defer c.Unlock()
	client := c.clients[name]
	delete(c.clients, name)
	if client != nil{
		client.Close()
	}
}


var cs *clients

func init()  {
	cs = &clients{
		clients: make(map[string]*redis.Client),
	}
}
func NewClient(name string) (client *redis.Client, err error){
	client = cs.get(name)
	if client != nil && client.Ping().Err() == nil{
		return
	}
	key := "redis." + name
	if !viper.IsSet(key) {
		err = errors.New(fmt.Sprintf(errConfigKeyNil, key))
		return
	}
	options := &redis.Options{
		Addr:         viper.GetString(key + ".addr"),
		Password:     viper.GetString(key + ".password"),
		DB:           viper.GetInt(key + ".db"),
		DialTimeout:  viper.GetDuration(key+".dialTimeout") * time.Millisecond,
		ReadTimeout:  viper.GetDuration(key+".readTimeout") * time.Millisecond,
		WriteTimeout: viper.GetDuration(key+".writeTimeout") * time.Millisecond,
		MaxRetries:   viper.GetInt(key + ".maxRetries"),
		PoolSize:     viper.GetInt(key + ".poolSize"),
		MinIdleConns: viper.GetInt(key + ".minIdleConns"),
	}
	
	idleTimeout := viper.GetDuration(key + ".idleTimeout")
	if idleTimeout > 0 {
		options.IdleTimeout = idleTimeout
	}
	
	client = redis.NewClient(options)
	if client.Ping().Err() == nil{
		cs.add(name, client)
	}
	
	return
}
